using System;
using System.Diagnostics;
using System.Web;
using System.Web.Configuration;
using System.Web.SessionState;
using facebook.Utility;


namespace facebook.web
{
	internal class BasePageHelper
	{
		private const string FACEBOOK_CANVAS_PARAM = "&canvas";
		private const string FACEBOOK_LOGIN_URL = @"http://www.facebook.com/login.php?api_key=";
		private const string QUERY_AUTH_TOKEN = "auth_token";
		private const string REQUEST_IN_CANVAS = "fb_sig_in_canvas";
        private const string REQUEST_IN_PROFILE_TAB = "fb_sig_in_profile_tab";
		private const string REQUEST_SESSION_KEY = "fb_sig_session_key";
		private const string REQUEST_USER_ID = "fb_sig_user";
        private const string REQUEST_PROFILE_SESSION_KEY = "fb_sig_profile_session_key";
        private const string REQUEST_PROFILE_USER_ID = "fb_sig_profile_user";
        private const string SESSION_SESSION_KEY = "SessionKey";
		private const string SESSION_USER_ID = "UserId";

		private readonly API api = new API();

		private readonly bool _autoAdd;
		private readonly HttpRequest _request;
		private readonly HttpResponse _response;
		private readonly HttpSessionState _session;
		private readonly bool _useSession;

		private BasePageHelper(API FaceBookAPI, bool useSession, bool autoAdd, HttpRequest request,
		                       HttpResponse response, HttpSessionState session)
		{
			api = FaceBookAPI;
			_useSession = useSession;
			_autoAdd = autoAdd;
			_request = request;
			_response = response;
			_session = session;
		}

		#region Public Static Methods

		public static void LoadFBMLPage(API FaceBookAPI, bool requireLogin, HttpRequest request, HttpResponse response)
		{
			string sessionKey = null;
			string userId = null;
			string inCanvas = request[REQUEST_IN_CANVAS];
            string inProfileTab = request[REQUEST_IN_PROFILE_TAB];

			FaceBookAPI.IsDesktopApplication = false;

            if (string.IsNullOrEmpty(FaceBookAPI.ApplicationKey) || string.IsNullOrEmpty(FaceBookAPI.Secret))
            {
                GetKeyAndSecretFromWebConfig(FaceBookAPI);
            }

            if (requireLogin)
            {
                if (string.IsNullOrEmpty(FaceBookAPI.SessionKey) || string.IsNullOrEmpty(FaceBookAPI.uid.ToString()))
                {
                    if (inProfileTab != "1")
                    {
                        sessionKey = request[REQUEST_SESSION_KEY];
                        userId = request[REQUEST_USER_ID];
                    }
                    else
                    {
                        sessionKey = request[REQUEST_PROFILE_SESSION_KEY];
                        userId = request[REQUEST_PROFILE_USER_ID];
                    }
                }
                else
                {
                    sessionKey = FaceBookAPI.SessionKey;
                    userId = FaceBookAPI.uid.ToString();
                }

                // When the user uses the facebook login page, the redirect back here will will have the auth_token in the query params
                string authToken = request.QueryString[QUERY_AUTH_TOKEN];

                // We have already established a session on behalf of this user
                if (!String.IsNullOrEmpty(sessionKey))
                {
                    FaceBookAPI.SessionKey = sessionKey;
                    FaceBookAPI.uid = long.Parse(userId);
                }
                //// This will be executed when facebook login redirects to our page
                else if (!String.IsNullOrEmpty(authToken))
                {
                    FaceBookAPI.CreateSession(authToken);
                }
                else
                {
                    if (inCanvas=="1")
                    {
						response.Write("<fb:redirect url=\"" + FACEBOOK_LOGIN_URL + FaceBookAPI.ApplicationKey + @"&v=1.0&next=" + GetCanvasURL(request) + "&canvas\"/>");

                    }
                    else
                    {
                        response.Write("<fb:redirect url=\"" + FACEBOOK_LOGIN_URL + FaceBookAPI.ApplicationKey + @"&v=1.0&next=" + GetCanvasURL(request) + "\"/>");
                    }
                    response.End();
                }
            }
		}

        internal static void GetKeyAndSecretFromWebConfig(API FaceBookAPI)
        {
            // ApplicationKey and Secret are acquired when you sign up for an application
            // Get the values from the configuration file.
            var apiKey = WebConfigurationManager.AppSettings["APIKey"];
            var secret = WebConfigurationManager.AppSettings["Secret"];

            if (apiKey == null || secret == null)
                throw new Exception(
                    "You must specify values for both APIKey and Secret in the web config of your project.\r\n" +
                    "For example: \r\n" +
                    "<appSettings> \r\n " +
                    "   <add key=\"APIKey\" value =\"YOURAPIKEY\"/>\r\n" +
                    "   <add key=\"Secret\" value =\"YOURSECRET\"/>\r\n" +
                    "</appSettings>\"");

            FaceBookAPI.ApplicationKey = apiKey;
            FaceBookAPI.Secret = secret;
        }

     

		public static void LoadIFramePage(API FaceBookAPI, bool useSession, bool autoAdd, HttpRequest request,
		                                  HttpResponse response, HttpSessionState session)
		{
            if (string.IsNullOrEmpty(FaceBookAPI.ApplicationKey) || string.IsNullOrEmpty(FaceBookAPI.Secret))
            {
                GetKeyAndSecretFromWebConfig(FaceBookAPI);
            }
			new BasePageHelper(FaceBookAPI, useSession, autoAdd, request, response, session).LoadIFramePage();
		}

		#endregion

		#region Private Methods

		private void LoadIFramePage()
		{
			api.IsDesktopApplication = false;

			// When the user uses the facebook login page, the redirect back here
			// will will have the auth_token in the query params
			string authToken = _request.QueryString[QUERY_AUTH_TOKEN];
			string sessionKey = null;
			string userId = null;

			if (string.IsNullOrEmpty(api.SessionKey) || string.IsNullOrEmpty(api.uid.ToString()))
			{
				sessionKey = _request[REQUEST_SESSION_KEY];
				userId = _request[REQUEST_USER_ID];
			}
			else
			{
				sessionKey = api.SessionKey;
				userId = api.uid.ToString();
			}
            Debug.WriteLine("sessionKey:" + sessionKey + " userId: "+ userId);
			// We have already established a session on behalf of this user
            if (_useSession)
            {
                EstablishSession(sessionKey, userId, authToken, true);
            }
		}

		private void EstablishSession(string sessionKey, string userId, string authToken, bool retry)
		{
			try
			{
				object sessionKeyFromSession = _useSession
				                               	? _session[SESSION_SESSION_KEY]
				                               	:
				                               		_request.Cookies[SESSION_SESSION_KEY];

				if (String.IsNullOrEmpty(sessionKey) && sessionKeyFromSession != null)
				{
					sessionKey = _useSession ? sessionKeyFromSession.ToString() : ((HttpCookie) sessionKeyFromSession).Value;
					userId = _useSession ? _session[SESSION_USER_ID].ToString() : _request.Cookies[SESSION_USER_ID].Value;
				}

				if (!String.IsNullOrEmpty(sessionKey))
				{
					api.SessionKey = sessionKey;
					api.uid = Convert.ToInt64(userId);
					SetSessionInfo(sessionKey, userId);
				}
				else if (!String.IsNullOrEmpty(authToken))
				{
					api.CreateSession(authToken);
					SetSessionInfo(api.SessionKey, api.uid.ToString());
				}
				else
				{
					RedirectToLogin();
					return;
				}

				TryAddApp();
			}
			catch (FacebookException e)
			{
                if (e.ErrorType == ErrorType.Timeout)
                {
                    if (retry)
                    {
                        ClearSessionInfo();
                        EstablishSession(null, null, authToken, false);
                    }
                    else
                    {
                        throw;
                    }
                }
			}
		}

		private void RedirectTopFrame(HttpResponse response, string url)
		{
			response.Write("<script type=\"text/javascript\">\n" +
			               "if (parent != self) \n" +
			               "top.location.href = \"" + url + @"&v=1.0" + "\";\n" +
			               "else self.location.href = \"" + url + @"&v=1.0" + "\";\n" +
			               "</script>");
			response.End();
		}

		private void SetSessionInfo(string sessionKey, string userId)
		{
			if (_useSession)
			{
				_session[SESSION_SESSION_KEY] = sessionKey;
				_session[SESSION_USER_ID] = userId;
			}
			else
			{
				_response.Cookies.Remove(SESSION_SESSION_KEY);
				_response.Cookies.Remove(SESSION_USER_ID);
				_response.Cookies.Add(new HttpCookie(SESSION_SESSION_KEY, sessionKey));
				_response.Cookies.Add(new HttpCookie(SESSION_USER_ID, userId));
			}
		}

		private void ClearSessionInfo()
		{
			if (_useSession)
			{
				_session[SESSION_SESSION_KEY] = null;
				_session[SESSION_USER_ID] = null;
			}
			else
			{
				_response.Cookies.Remove(SESSION_SESSION_KEY);
				_response.Cookies.Remove(SESSION_USER_ID);
			}
		}

		private void TryAddApp()
		{
			if (!_autoAdd) return; //Removed: !api.users.isAppAdded()

			if (api.SessionKey != null)
			{
                if (_response.Cookies[SESSION_SESSION_KEY] != null)
                    _response.Cookies.Remove(SESSION_SESSION_KEY);
                if (_response.Cookies[SESSION_USER_ID] != null)
                    _response.Cookies.Remove(SESSION_USER_ID);
				//RedirectTopFrame(_response, FACEBOOK_ADD_URL + api.ApplicationKey);
			}
			else
			{
				RedirectToLogin();
			}
		}

		private void RedirectToLogin()
		{
			RedirectTopFrame(_response, FACEBOOK_LOGIN_URL + api.ApplicationKey + FACEBOOK_CANVAS_PARAM);
		}

		/// <summary>
		/// Converts the relative part of the URL being requested into a relative URL that can be called from the canvas page,
		/// taking into account whether or not the application is actually in a subdirectory of the web application.
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
        private static string GetCanvasURL(HttpRequest request)
        {
            string webApplicationSubdirectory = WebConfigurationManager.AppSettings["WebApplicationSubdirectory"];

            if (webApplicationSubdirectory == null)
            {
                webApplicationSubdirectory = string.Empty;
            }

            string relativeURL = request.AppRelativeCurrentExecutionFilePath.Substring(2);

            if (relativeURL.StartsWith(webApplicationSubdirectory))
            {
                relativeURL = relativeURL.Substring(webApplicationSubdirectory.Length);
            }

            string query = request.QueryString.ToString();
            if (!string.IsNullOrEmpty(query))
                relativeURL = System.Web.HttpUtility.UrlEncode(relativeURL + "?" + query);

            return relativeURL;
        }
		#endregion
	}
}